package com.infomass.mmds.web.service.report;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.infomass.framework.common.constants.YesOrNoConstants;
import com.infomass.framework.common.dto.Pagination;
import com.infomass.framework.common.dto.measuredata.RoutineDTO;
import com.infomass.framework.common.dto.measuredata.SampleDTO;
import com.infomass.framework.common.dto.oss.MailAttachementDTO;
import com.infomass.framework.common.dto.oss.MailDTO;
import com.infomass.framework.common.dto.oss.MailReceiveDTO;
import com.infomass.framework.common.dto.user.UserDTO;
import com.infomass.framework.common.enums.LangEnum;
import com.infomass.framework.common.enums.oss.MailTypeEnum;
import com.infomass.framework.common.feign.measuredata.RoutineFeignClient;
import com.infomass.framework.common.feign.measuredata.SampleFeignClient;
import com.infomass.framework.common.feign.oss.MailFeignClient;
import com.infomass.framework.common.feign.oss.OssFeignClient;
import com.infomass.framework.common.feign.user.UserFeignClient;
import com.infomass.framework.common.response.ApiResponse;
import com.infomass.framework.common.response.CommonResponseCode;
import com.infomass.mmds.web.dto.report.MeasurementReportDTO;
import com.infomass.mmds.web.entity.ExtraEntity;
import com.infomass.mmds.web.entity.PK;
import com.infomass.mmds.web.entity.report.GeneralReportEntity;
import com.infomass.mmds.web.entity.report.MeasurementReportEntity;
import com.infomass.mmds.web.repository.report.MeasurementReportRepository;
import com.infomass.mmds.web.service.BaseService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.io.ZipInputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.util.Asserts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.util.CastUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.persistence.Column;
import javax.persistence.Table;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
 * 测量报告
 * @author yw
 * 2020.9.18
 */
@Service
@Slf4j
public class MeasurementReportService extends BaseService {

    @Autowired
    private MeasurementReportRepository measurementReportRepository;
    
    @Autowired
    private RoutineFeignClient routineFeignClient;
    
    @Autowired
    private UserFeignClient userFeignClient;
    
    @Autowired
    private GeneralReportService generalReportService;
    
    @Autowired
    private SampleFeignClient sampleFeignClient;

    /**
     * 分页
     */
    @SuppressWarnings("unchecked")
	public Pagination findPage(PageRequest pageRequest, Map<String, Object> params) {
        if (params.get("order") == null) {
            params.put("order", "createTime desc");
        }
        List<String> routineIds = (List<String>) params.get("routineIds");
        
        /**通过样本筛选器查询符合条件的样本 BEGIN**/
        Map<String, Object> request = new HashMap<>();
        BeanUtil.copyProperties(params, request);
        if (request.containsKey("source")) {
            request.remove("source");
        }
        if (request.containsKey("generalReportTypeId")) {
            request.remove("generalReportTypeId");
        }
        if (request.containsKey("order")) {
            request.remove("order");
        }
        if (request.containsKey("routineIds")) {
            request.remove("routineIds");
        }
        if (request.containsKey("dateStart")) {
            request.remove("dateStart");
        }
        if (request.containsKey("dateEnd")) {
            request.remove("dateEnd");
        }
        if (request.containsKey("sampleLabel_LIKE")) {
        	request.remove("sampleLabel_LIKE");
        }

        if (CollUtil.isNotEmpty(request)) {
        	// 原先查询参数移除掉样本筛选器查询参数
            for (Map.Entry<String, Object> item : request.entrySet()) {
                if (params.containsKey(item.getKey())) {
                    params.remove(item.getKey());
                }
            }
            
            if(CollUtil.isNotEmpty(routineIds)) {
            	request.put("rId_IN", routineIds);
            }
            List<String> sIdList = sampleFeignClient.findSIdList(request);
            // 样本筛选器
            if (CollUtil.isEmpty(sIdList)) {
                return new Pagination();
            }
            params.put("sampleId_IN", sIdList);
        }
        /**通过样本筛选器查询符合条件的样本 END**/
        
        // 2021-08-03 直接通过数据库查询数据
        //模板类型
//        if (params.get("templateType") != null) {
//            int templateType = Integer.parseInt(params.get("templateType").toString());
//            List<GeneralReportResponse> generalReportResponses = generalReportService.findReportTemplateType(templateType);
//            if (generalReportResponses != null && generalReportResponses.size() > 0) {
//                List<String> generalReportIds = generalReportResponses.stream().map(GeneralReportResponse::getId).collect(Collectors.toList());
//                params.put("generalReportId_IN", generalReportIds);
//            } else {
//                return new Pagination();
//            }
//            params.remove("templateType");
//        }

        Page<MeasurementReportEntity> page = measurementReportRepository.findPageByHql(pageRequest, "findList", params);
        return new Pagination(page, (list) -> {
            if (CollUtil.isEmpty(list)) {
                return null;
            }

            List<String> routineIdList = new ArrayList<>();
            List<String> sampleIdList = new ArrayList<>();
            List<String> userIdList = new ArrayList<>();
            List<String> generateReportIdList = new ArrayList<>();

            page.getContent().stream().forEach(p -> {
                if (StrUtil.isNotBlank(p.getRoutineId())) {
                    routineIdList.add(p.getRoutineId());
                }
                if (StrUtil.isNotBlank(p.getCreatorId())) {
                    userIdList.add(p.getRoutineId());
                }
                if (StrUtil.isNotBlank(p.getGeneralReportId())) {
                    generateReportIdList.add(p.getGeneralReportId());
                }
                if (StrUtil.isNotBlank(p.getSampleId())) {
                	sampleIdList.add(p.getSampleId());
                }
            });

            List<SampleDTO> sampleList = sampleFeignClient.findByIdList(sampleIdList);

            List<RoutineDTO> routineList = routineFeignClient.findByIdList(routineIdList);
            List<UserDTO> userList = userFeignClient.getUserList(userIdList);
            List<GeneralReportEntity> generalReportList = new ArrayList<>();
            params.clear();
            params.put("id_IN", generateReportIdList);
            if (!params.isEmpty()) {
                generalReportList = generalReportService.findList(params);
            }

            // 实体类转response
            List<MeasurementReportDTO> resultList = new ArrayList<>();
            for (Object obj : list) {
                MeasurementReportDTO measurementReportDto = new MeasurementReportDTO();
                MeasurementReportEntity measurementReportEntity = (MeasurementReportEntity) obj;

                // 复制样本筛选器
                Optional<SampleDTO> first = sampleList.stream().filter(p -> p.getId().equals(measurementReportEntity.getSampleId())).findFirst();
                if (first.isPresent()) {
                    BeanUtil.copyProperties(first.get(), measurementReportDto, new String[]{"id", "rId", "label", "descr","seq","createDate","importDate","routineLable","passrate"});
                }

                // 复制相同属性
                BeanUtil.copyProperties(measurementReportEntity, measurementReportDto);
                measurementReportDto.setId(measurementReportEntity.getPk().getId());

                // 设置报告名称
                if (StrUtil.isNotBlank(measurementReportEntity.getGeneralReportId()) && CollUtil.isNotEmpty(generalReportList)) {
                    Optional<GeneralReportEntity> op = generalReportList.stream().filter(p -> p.getPk().getId().equals(measurementReportEntity.getGeneralReportId())).findFirst();
                    measurementReportDto.setGeneralReportName(op.isPresent() ? op.get().getName() : null);
                }

                // 设置零件名称
                if (StrUtil.isNotBlank(measurementReportEntity.getRoutineId()) && CollUtil.isNotEmpty(routineList)) {
                    Optional<RoutineDTO> op = routineList.stream().filter(p -> p.getId().equals(measurementReportEntity.getRoutineId())).findFirst();
                    measurementReportDto.setRoutineLabel(op.isPresent() ? op.get().getLabel() : null);
                    measurementReportDto.setName(op.isPresent() && StrUtil.isNotBlank(op.get().getDescr()) ? op.get().getDescr() : measurementReportDto.getName());
                }
                
                // 创建人
                if (StrUtil.isNotBlank(measurementReportEntity.getCreatorId()) && CollUtil.isNotEmpty(userList)) {
                    Optional<UserDTO> op = userList.stream().filter(p -> p.getId().equals(measurementReportEntity.getCreatorId())).findFirst();
                    measurementReportDto.setCreatorName(op.isPresent() ? op.get().getName() : null);
                }
                resultList.add(measurementReportDto);
            }

            return resultList;
        });
    }


    /**
     * 删除
     */
    public void delete(String id) {
        MeasurementReportEntity measurementReportEntity = measurementReportRepository.getOne(new PK(id, getCurrentLang()));
        measurementReportEntity.setIsDeleted(YesOrNoConstants.YES);
        measurementReportRepository.save(measurementReportEntity);
    }

    /**
     * 保存
     */
    public void save(MeasurementReportEntity measurementReportEntity) {
        measurementReportRepository.save(measurementReportEntity);
    }

    /**
     * 列表
     */
    public List<MeasurementReportEntity> findList(Map<String, Object> params) {
        if (params.get("order") == null) {
            params.put("order", "createTime desc");
        }
        return measurementReportRepository.findAllByHql("findList", params);
    }
    
    /**
     * 测量报告
     */
    public MeasurementReportEntity findById(String id) {
        return measurementReportRepository.getOne(new PK(id, getCurrentLang()));
    }

    /**
     * 通过零件ID对应的自动报告数据
     *
     * @return
     */
    public List<MeasurementReportEntity> getAutoReport(String reportId) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("source", MeasurementReportEntity.SOURCE_AUTO);
        params.put("generalReportId", reportId);
        params.put("generalReportLang", getCurrentLang());
        return findList(params);
    }

    /**
     * 测量报告管理数量
     */
    public int count(Map<String, Object> params) {
        int page = 1;
        int size = 1;
        Sort sorted = Sort.unsorted();
        PageRequest pageRequest = PageRequest.of(page, size, sorted);
        if (params.get("createTime_GTE") != null) {
            params.put("createTime_GTE",  DateUtil.parseDateTime(CastUtils.cast(params.get("createTime_GTE"))));
        }
        if (params.get("createTime_LTE") != null) {
            params.put("createTime_LTE",  DateUtil.parseDateTime(CastUtils.cast(params.get("createTime_LTE"))));
        }
        params.put("isDelete", YesOrNoConstants.NO);
        Page<MeasurementReportEntity> measurementReportPage = measurementReportRepository.findPageByHql(pageRequest, "findList", params);
        int number = measurementReportPage.getTotalPages();
        return number;
    }

    public int dataSummaryCount(Map<String, Object> params) {
        String sql = CastUtils.cast(params.get("sql"));
        params.remove("sql");
        List<Map<String, Object>> byNativeQuery = measurementReportRepository.findByNativeQuery(sql, params);
        return (int) Stream.of(byNativeQuery).filter(Objects::nonNull).flatMap(List::stream)
                .map(m -> {
                    BigInteger ct = CastUtils.cast(m.get("ct"));
                    return Optional.ofNullable(ct).map(mp -> mp.intValue()).orElseGet(() -> 0);
                }).mapToInt(mi->mi).sum();

    }

    public List<com.infomass.framework.common.dto.web.MeasurementReportDTO> dataSummaryFindList(Map<String, Object> params) {
        String sql = CastUtils.cast(params.get("sql"));
        params.remove("sql");
        List<Map<String, Object>> byNativeQuery = measurementReportRepository.findByNativeQuery(sql, params);

        return Stream.of(byNativeQuery).filter(Objects::nonNull).flatMap(List::stream)
                .map(m ->
                        BeanUtil.mapToBean(m, com.infomass.framework.common.dto.web.MeasurementReportDTO.class, false, new CopyOptions())
                ).collect(Collectors.toList());
    }

    @Autowired
    private OssFeignClient ossFeignClient;
    /** 向量密钥，可以自定义，必须128位(16字节) */
    private static final String PARAM_KEY ="5mb25fz3I$ggMjA=";
    private static final String CIPHER_KEY = "AES/CBC/PKCS5Padding";
    private static final String CHARSET = "utf-8";
    public static final String MODE_AES = "AES";
    @Autowired
    private MailFeignClient mailFeignClient;
    @Autowired
    private MeasurementReportService measurementReportService;

    /**
     * @param params
     * @Author huangming  2024/2/20 11:39
     * @Description:  手动报告发送 供应商-》主机厂
     **/
    @SneakyThrows
    public void manualSend(Map<String, Object> params) {

        List<String> idList = CastUtils.cast(params.getOrDefault("idList", Lists.newArrayList()));
        Assert.notEmpty(idList,StringUtils.EMPTY);
        List<String> routineNameList = CastUtils.cast(params.getOrDefault("routineNameList", Lists.newArrayList()));
        List<String> recipientList = CastUtils.cast(params.getOrDefault("recipientList", Lists.newArrayList()));
        List<String> ccRecipientList = CastUtils.cast(params.getOrDefault("ccRecipientList", Lists.newArrayList()));
        String titleContent = CastUtils.cast(params.getOrDefault("titleContent",StringUtils.EMPTY));

        int reportSwitch = CastUtils.cast(params.getOrDefault("reportSwitch",0));
        boolean reportAutoBool = CastUtils.cast(params.getOrDefault("reportAutoBool",false));

        //手动发送测量报告的时候 由于可以批量发送报告 一封邮件多个零件
        if(!reportAutoBool){
            //待发送数据的Map
            Map<String,Object> sendDataMap = Maps.newHashMap();

            Map<String, Object> queryParams = Maps.newHashMapWithExpectedSize(8);
            queryParams.put("id_IN", idList);
            List<MeasurementReportEntity> measurementReportEntityList = measurementReportService.findList(queryParams);
            sendDataMap.put("MeasurementReportEntityList", measurementReportEntityList);


            //发送模板
            if(Objects.equals(1,reportSwitch))  {
                List<GeneralReportEntity> generalReportEntityList = generalReportService.findByIdIn(measurementReportEntityList.stream().map(MeasurementReportEntity::getGeneralReportId).collect(Collectors.toList()));
                sendDataMap.put("GeneralReportEntityList", generalReportEntityList);
                sendDataMap.put("reportJsonList",generalReportEntityList.stream().map(m->generalReportService.getJson(m.getJson())).collect(Collectors.toList()));
            }

            //内部邮件内容
            sendDataMap.put("titleContent",titleContent);
            String title = String.join("", Arrays.asList("供应商", String.join(",", routineNameList), DateUtil.formatDateTime(new Date())));

            //外部邮件内容
            StringBuilder contentBuilder = new StringBuilder();
            contentBuilder.append("零件编号：").append(String.join(",", routineNameList)).append("\n\r");
            contentBuilder.append("模板：").append(0 == reportSwitch ? 0 : idList.size()).append("\n\r");
            contentBuilder.append("报告：").append(idList.size()).append("\n\r");
            contentBuilder.append("样本：").append(0);

            MailDTO mailDTO = new MailDTO(){
                {
                    this.setFiles(Lists.newArrayList());
                    this.setFileNames(Lists.newArrayList());
                }
            };
            mailDTO.setMailType(MailTypeEnum.MAUANL_REPORT);
            mailDTO.setTitleValues(CollUtil.newArrayList(title));
            mailDTO.setSendMethod(1);
            mailDTO.setValues(CollUtil.newArrayList(contentBuilder.toString()));
            mailDTO.setTargets(recipientList);
            mailDTO.setCc(ccRecipientList);

            List<File> fileList = Lists.newArrayList();

            String basePath = cn.hutool.core.io.FileUtil.getTmpDirPath();

            String dataPath = basePath + "/" + com.infomass.framework.common.util.DateUtil.format(new Date(), "yyyyMMddHHmmss") + ".txt";

            File dataFile = new File(dataPath);
            dataFile.createNewFile();

            for(MeasurementReportEntity measurementReportEntity : measurementReportEntityList){
                String tempBasePath = cn.hutool.core.io.FileUtil.getTmpDirPath();
                String filePath = tempBasePath + "/" + com.infomass.framework.common.util.DateUtil.format(new Date(), "yyyyMMddHHmmss") + ".pdf";
                File tempFile = new File(filePath);
                tempFile.createNewFile();

                byte[] measurementReport = ossFeignClient.getRemoteFileBytes(measurementReportEntity.getUrl());
//                byte[] compressedMeasurementReport = this.compressData(measurementReport);
//                String compressedSendData = new String(this.compressData(JSONObject.toJSONString(sendDataMap).getBytes()));

                //附件
//                String encrypt = this.encrypt(new String(compressedMeasurementReport), "123456");
//                mailDTO.getFiles().add(encrypt.getBytes());

//                String data = this.encrypt(compressedSendData, "123456");
//                mailDTO.getFiles().add(data.getBytes());


                try (FileOutputStream fileOutputStream = new FileOutputStream(tempFile, true)) {
                    fileOutputStream.write(measurementReport);
                    fileList.add(tempFile);
                }

//                mailDTO.getFileNames().add(measurementReportEntity.getName());
//                mailDTO.getFileNames().add(measurementReportEntity.getName() + "数据文件");

            }

            try (FileOutputStream fileOutputStream = new FileOutputStream(dataFile, true)) {
                fileOutputStream.write(sendDataMap.toString().getBytes());
                fileList.add(dataFile);
            }

            ZipFile zip = this.zip("data.zip", fileList, "123456");
            byte[] bytes = IoUtil.readBytes(new FileInputStream(zip.getFile()), true);

            mailDTO.getFiles().add(bytes);
            mailDTO.getFileNames().add("数据文件.zip");

            ApiResponse apiResponse = mailFeignClient.sendHTMLAndAttachmentMail(mailDTO);
            Asserts.check(apiResponse.getCode() == CommonResponseCode.OK.getCode(),apiResponse.getMsg());

            //TODO 保存供应商邮件发送记录  新增一张表 区别于普通的邮件发送记录表
            return;
        }


        Map<String, Object> queryParams = Maps.newHashMapWithExpectedSize(8);
        queryParams.put("id_IN", idList);
        List<MeasurementReportEntity> measurementReportEntityList = measurementReportService.findList(queryParams);
        List<String> rIdList = measurementReportEntityList.stream().map(MeasurementReportEntity::getRoutineId).distinct().collect(Collectors.toList());
        List<RoutineDTO> routineDTOList = routineFeignClient.findByIdList(rIdList);
        routineNameList = routineDTOList.stream().map(RoutineDTO::getLabel).collect(Collectors.toList());

        //模板自动发送的时候 一个零件 一封邮件
        int index =0;
        for(String id : idList){

            MeasurementReportEntity measurementReportEntity = measurementReportRepository.getOne(new PK(id, getCurrentLang()));
            Assert.notNull(measurementReportEntity,StringUtils.EMPTY);

            //待发送数据的Map
            Map<String,Object> sendDataMap = Maps.newHashMap();

            //发送样本
            Map<String,Object> bodyMap = CastUtils.cast(redisUtil.get(String.format("sendMessage_%s", measurementReportEntity.getSampleId())));
            sendDataMap.put("bodyMap",bodyMap);

            //内部邮件内容
            sendDataMap.put("titleContent",titleContent);
            String title = String.join("", Arrays.asList("供应商", String.join(",", routineNameList), DateUtil.formatDateTime(new Date())));

            //外部邮件内容
            StringBuilder contentBuilder = new StringBuilder();
            contentBuilder.append("零件编号：").append(routineNameList.get(index++)).append("\n\r");
            contentBuilder.append("模板：").append(0 == reportSwitch ? 0 : idList.size()).append("\n\r");
            contentBuilder.append("报告：").append(idList.size()).append("\n\r");
            contentBuilder.append("样本：").append(0);

            MailDTO mailDTO = new MailDTO();
            mailDTO.setMailType(MailTypeEnum.MAUANL_REPORT);
            mailDTO.setTitleValues(CollUtil.newArrayList(title));
            mailDTO.setSendMethod(1);
            mailDTO.setValues(CollUtil.newArrayList(contentBuilder.toString()));
            mailDTO.setTargets(recipientList);
            mailDTO.setCc(ccRecipientList);

            //发送模板
            if(Objects.equals(1,reportSwitch))  {
                String generalReportId = measurementReportEntity.getGeneralReportId();
                GeneralReportEntity generalReport = generalReportService.findById(generalReportId);
                String reportJson =  generalReportService.getJson(generalReport.getJson());

                sendDataMap.put("GeneralReportEntityList", Collections.singletonList(generalReport));
                sendDataMap.put("reportJsonList", Collections.singletonList(reportJson));
            }

            //发送测量报告
            sendDataMap.put("MeasurementReportEntityList", Collections.singletonList(measurementReportEntity));

            byte[] measurementReport = ossFeignClient.getRemoteFileBytes(measurementReportEntity.getUrl());
            byte[] compressedMeasurementReport = this.compressData(measurementReport);
            String compressedSendData = new String(this.compressData(JSONObject.toJSONString(sendDataMap).getBytes()));

            //附件
            mailDTO.setFiles(new ArrayList(){
                {
                    String encrypt = encrypt(new String(compressedMeasurementReport), "123456");
                    add(encrypt.getBytes());
                    encrypt = encrypt(compressedSendData, "123456");
                    add(encrypt.getBytes());
                }
            });
            mailDTO.setFileNames(new ArrayList(){
                {
//                    add(measurementReportEntity.getName());
                    add(measurementReportEntity.getName() + "数据文件");
                }
            });

            ApiResponse apiResponse = mailFeignClient.sendHTMLAndAttachmentMail(mailDTO);
            Asserts.check(apiResponse.getCode() == CommonResponseCode.OK.getCode(),apiResponse.getMsg());

            if(sendDataMap.containsKey("bodyMap")){
                //删除Redis里面的key
                redisUtil.del(String.format("sendMessage_%s", measurementReportEntity.getSampleId()));
            }

            //TODO 保存供应商邮件发送记录  新增一张表 区别于普通的邮件发送记录表

        }

    }
    /**
     * @param data
     * @Author huangming  2024/2/21 15:19
     * @Description: 压缩数据
     **/
    public byte[] compressData(byte[] data) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
        gzipOutputStream.write(data);
        gzipOutputStream.close();
        return byteArrayOutputStream.toByteArray();
    }

    public  String decompressData(byte[] gzipData) throws IOException {
        // 解压缩数据
        ByteArrayOutputStream uncompressedStream = new ByteArrayOutputStream();
        try (GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(gzipData))) {
            byte[] buffer = new byte[1024];
            int count;
            while ((count = gzipInputStream.read(buffer)) != -1) {
                uncompressedStream.write(buffer, 0, count);
            }
        }
        byte[] uncompressedData = uncompressedStream.toByteArray();
        return new String(uncompressedData, StandardCharsets.UTF_8);
    }
    /**
     * @Author huangming  2024/2/21 18:16
     * @Description: 获取原始SQL
     **/
    @SneakyThrows
    public String getSql(ExtraEntity extraEntity){
        // 获取实体类的所有字段
        Field[] fields = this.getAllFields(extraEntity.getClass());

        Table tableAnnotation = extraEntity.getClass().getAnnotation(Table.class);

        StringBuilder builder = new StringBuilder();
        builder.append("INSERT INTO ");
        builder.append(tableAnnotation.name());
        builder.append(" (");

        for (Field field : fields) {
            field.setAccessible(true);
            String columnName  = field.getName();
            if(Modifier.isStatic(field.getModifiers())){
                continue;
            }

            if (field.isAnnotationPresent(Column.class)) {
                Column columnAnnotation = field.getAnnotation(Column.class);
                columnName = columnAnnotation.name();
            }

            if(columnName.contains("pk")){
                Field[] pkFields = PK.class.getDeclaredFields();
                for(Field fd : pkFields){
                    fd.setAccessible(true);
                    if(Modifier.isStatic(fd.getModifiers())){
                        continue;
                    }
                    builder.append(this.camelCaseToSnakeCase(fd.getName())).append(", ");
                }

                continue;
            }
            builder.append(this.camelCaseToSnakeCase(columnName)).append(", ");
        }

        builder.delete(builder.length() - 2, builder.length()); // 移除最后一个逗号和空格
        builder.append(") VALUES (");

        for (Field field : fields) {
            field.setAccessible(true);
            if(Modifier.isStatic(field.getModifiers())){
                continue;
            }

            Object value = field.get(extraEntity);
            if (value instanceof String || value instanceof Date || value instanceof LangEnum) {
                if(field.getName().contains("pk")){
                    Field[] pkFields = PK.class.getDeclaredFields();
                    for(Field fd : pkFields){
                        fd.setAccessible(true);
                        if(Modifier.isStatic(fd.getModifiers())){
                            continue;
                        }
                        builder.append("'").append(fd.get(value)).append("', ");
                    }
                    continue;
                }
                builder.append("'").append(value).append("', ");

            } else {
                if(field.getName().contains("pk")){
                    Field[] pkFields = PK.class.getDeclaredFields();
                    for(Field fd : pkFields){
                        fd.setAccessible(true);
                        if(Modifier.isStatic(fd.getModifiers())){
                            continue;
                        }
                        builder.append("'").append(fd.get(value)).append("', ");
                    }

                    continue;
                }
                builder.append(value).append(", ");
            }
        }

        builder.delete(builder.length() - 2, builder.length()); // 移除最后一个逗号和空格
        builder.append(")");

        return builder.toString();
    }

    public String camelCaseToSnakeCase(String input) {
        String regex = "([a-z\\d])([A-Z])";
        String replacement = "$1_$2";

        return input.replaceAll(regex, replacement).toLowerCase();
    }

    public Field[] getAllFields(Class<?> clazz) {
        // 递归获取所有字段，包括父类的字段
        List<Field> fieldList = new ArrayList<>();
        while (clazz != null) {
            // 获取当前类的所有字段，并添加到列表中
            fieldList.addAll(Arrays.asList(clazz.getDeclaredFields()));
            // 获取父类，直到父类为空为止
            clazz = clazz.getSuperclass();
        }
        return fieldList.toArray(new Field[0]);
    }

    /**
     * @param
     * @Author huangming  2024/2/23 15:21
     * @Description: 一键刷新 获取邮件
     **/
    @SneakyThrows
    public void receiveEmail(Map<String, Object> params) {

        ApiResponse receive = mailFeignClient.receive(params);

        List<Map> receiveMap = CastUtils.cast(receive.getData());
        List<MailReceiveDTO> mailReceiveDTOList = receiveMap.stream().map(m-> BeanUtil.mapToBean(m,MailReceiveDTO.class,false,new CopyOptions())).collect(Collectors.toList());

        for(MailReceiveDTO mailReceiveDTO : mailReceiveDTOList){

            List<MailAttachementDTO> attachementList = mailReceiveDTO.getAttachementList();
            attachementList = CollectionUtil.isNotEmpty(attachementList) ? attachementList : Lists.newArrayList();

            for (MailAttachementDTO mailAttachementDTO : attachementList) {
                log.info("content:{}",new String(mailAttachementDTO.getContent(),"UTF-8"));
//                byte[] decrypt = this.decrypt(new String(mailAttachementDTO.getContent()), "123456");
//                String result  = this.decompressData(decrypt);
                //解析数据
            }
        }
    }


    @SneakyThrows
    public String encrypt(String sSrc, String sKey) {
        Cipher cipher = Cipher.getInstance(CIPHER_KEY);
        KeyGenerator kgen = KeyGenerator.getInstance(MODE_AES);
        kgen.init(128, new SecureRandom(sKey.getBytes(CHARSET)));
        SecretKey secretKey = kgen.generateKey();
        IvParameterSpec iv = new IvParameterSpec(PARAM_KEY.getBytes(CHARSET));
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
        byte[] encrypted = cipher.doFinal(sSrc.getBytes(CHARSET));
        return cn.hutool.core.codec.Base64.encode(encrypted);
    }


    @SneakyThrows
    public byte[] decrypt(String sSrc, String sKey) {
        Cipher cipher = Cipher.getInstance(CIPHER_KEY);
        KeyGenerator kgen = KeyGenerator.getInstance(MODE_AES);
        kgen.init(128, new SecureRandom(sKey.getBytes(CHARSET)));
        SecretKey secretKey = kgen.generateKey();
        IvParameterSpec iv = new IvParameterSpec(PARAM_KEY.getBytes(CHARSET));
        cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
        return cipher.doFinal(cn.hutool.core.codec.Base64.decode(sSrc));
    }

    @SneakyThrows
    public ZipFile zip(String zipName,List<File> fileList,String password){
        //This is name and path of zip file to be created
        net.lingala.zip4j.core.ZipFile zipFile = new ZipFile(zipName);

        //Add files to be archived into zip file
        ArrayList<File> filesToAdd = Lists.newArrayList();
        filesToAdd.addAll(fileList);

        //Initiate Zip Parameters which define various properties
        ZipParameters parameters = new ZipParameters();
        parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); // set compression method to deflate compression

        //DEFLATE_LEVEL_FASTEST 	- Lowest compression level but higher speed of compression
        //DEFLATE_LEVEL_FAST 		- Low compression level but higher speed of compression
        //DEFLATE_LEVEL_NORMAL 	- Optimal balance between compression level/speed
        //DEFLATE_LEVEL_MAXIMUM 	- High compression level with a compromise of speed
        //DEFLATE_LEVEL_ULTRA 		- Highest compression level but low speed
        parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);

        //Set the encryption flag to true
        parameters.setEncryptFiles(true);

        //Set the encryption method to AES Zip Encryption
        parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);

        //AES_STRENGTH_128 - For both encryption and decryption
        //AES_STRENGTH_192 - For decryption only
        //AES_STRENGTH_256 - For both encryption and decryption
        //Key strength 192 cannot be used for encryption. But if a zip file already has a
        //file encrypted with key strength of 192, then Zip4j can decrypt this file
        parameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);

        //Set password
        parameters.setPassword(password);

        //Now add files to the zip file
        zipFile.addFiles(filesToAdd, parameters);

        return zipFile;
    }

    @SneakyThrows
    public void unzip(String zipName,String password){
        ZipFile zipFile = new ZipFile(zipName);
        if (zipFile.isEncrypted()) {
            zipFile.setPassword(password);
        }
        List<FileHeader> fileList = zipFile.getFileHeaders();
        for (FileHeader fileHeader : fileList) {
            ZipInputStream inputStream = zipFile.getInputStream(fileHeader);

            // 如果是文件，就先创建一个文件，然后用io流把内容copy过去
            File targetFile = new File(cn.hutool.core.io.FileUtil.getTmpDirPath() + "/" + fileHeader.getFileName());

            FileOutputStream fos = new FileOutputStream(targetFile);
            int len;
            byte[] buf = new byte[1024];
            while ((len = inputStream.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }
            // 关流顺序，先打开的后关闭
            fos.close();
            inputStream.close();
        }
        FileUtil.del(zipFile.getFile());
    }
}
